package edu.upenn.seas.peerreview.smui
import edu.upenn.seas.peerreview.{Id, Source, Sink}
  
/* ********************************************************** */

abstract class BSHandler(myId:Id, transport: Sink.T) extends Source.T {
  
  protected val debug=edu.upenn.seas.peerreview.Debug.debug("appmessage")(_)
  private var goingToAudit: Id = null

  def idstr(i: Id) = i match {
    case null => "null"
    case x if x == myId => "me"
    case x => x.toString
  }
  def debug_envelope(direction: String, e: Envelope) {
    debug("%-15s %s: %15s --> %-15s | %s".format(myId, direction, idstr(e.from), idstr(e.to), e.contents))
  }

  def handle(e: Envelope)
  
  // To fulfill the Source.T: Incoming message.
  def apply(from : Id, message : Message) {
    message match {
      case e: Envelope => { 
        debug_envelope("recv", e)
        if (from != e.from) error("Forged message. Actual sender is: " + 
                                    " but envelope says " + e)
        handle(e)
      }
      
      //      case m: RPC.RPCMessage =>
      //debug("got rpc message, ignored.")

      case AuditResult(r) => {
        println("[%s] Audit results: %s was %s".format(myId, goingToAudit, if (r) "not cheating." else "CHEATING!"))
      }
      
      case _ => error("Didn't get an envelope, instead received: " + message)
    }
  }
 
  def send(to: Id, contents: Payload) {
    val e = Envelope(myId, to, contents)
    debug_envelope("send", e)
    transport(to, e)
  }

  final def send(to: Id, m: Message) {
    m match {
      case PleaseAudit(opp: Id) => goingToAudit = opp // Save the auditee.
      case _ => 
    }
    transport(to, m)
  }
  
  
  def broadcast(to: Id, cc: Collection[Id], contents: Payload) {
    //treeset, to ensure deterministic order
    val cc_set = Set[Id]() ++ cc
    val recipients = if (to == null) cc_set else cc_set + to
    val e = Envelope(myId, to, contents)
    debug_envelope("bcst", e)
    for (ccid <- recipients) 
      send(ccid, e)
    
  }
}

case class Envelope(from: Id, to: Id, contents: Payload) extends Message 

// Result options following an attempted hit.
abstract class FireResultType {}
case object Hit extends FireResultType
case object Miss extends FireResultType
case object Sunk extends FireResultType
case object Defeat extends FireResultType
case object RedundantHit extends FireResultType

// Payload types.
abstract class Payload

/** Notification of Manager to register with NameServer. */
case class RegisterTournament(name : String) extends Payload
/** Request the Id of a tournmanet. */
case class RequestId(name : String) extends Payload
/** Return the Id of a tournament. */
case class ReturnId(id : Id) extends Payload


/** Notification to BSM to join the game. */
case class JoinServer() extends Payload
/** Distribution of current game configurations. */
case class NewGameConfigs(opponents:List[Id], boardSize:Point, ships:List[Int]) 
    extends Payload
/** Request for a fire action from SM to UI. */
case class RequestAction() extends Payload
/** Placement of a ship on the board. */
case class PlaceShip(bow:Point, stern:Point) extends Payload
/** Notification that all ships are placed and firing may begin. */
case class ReadyToPlay() extends Payload
/** Fire at a specific point at a given target opponent. */
case class FireAt(place:Point, target:Id) extends Payload
/** Notification to (non-fired-at) opponents that you've made a move this round. */
case class MoveMade() extends Payload
/** Result of a FireAt directive. */
case class FireResult(source:Envelope,result:FireResultType) extends Payload
/** Summary of a player's performance when he has been defeated. */
case class PlayerResult(numHits:Int,numSunks:Int,numKills:Int,isWinner:Boolean) 
    extends Payload
/** Request from SM to drop out of the game (out of courtesy).*/
case class LetMeLeave() extends Payload
/** Notice from BSM to SMs that a player was dropped, either because he 
 requested it, or because of possibly suspicious/inactivity node. */
case class PlayerWithdrawal(removedPlayer:Id) extends Payload

/** A forwarded message. */
case class Forward(from: Id, message : Payload) extends Payload

case class GameOver() extends Payload
case class TournamentOver() extends Payload

//ui announces its existence to its sm
case class IAmYourUI() extends Payload
